// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// package main -- go2cs converted at 2022 March 13 05:58:11 UTC
// Original source: C:\Program Files\Go\src\cmd\cgo\godefs.go
namespace go;

using bytes = bytes_package;
using fmt = fmt_package;
using ast = go.ast_package;
using printer = go.printer_package;
using token = go.token_package;
using os = os_package;
using filepath = path.filepath_package;
using strings = strings_package;


// godefs returns the output for -godefs mode.

public static partial class main_package {

private static @string godefs(this ptr<Package> _addr_p, ptr<File> _addr_f) {
    ref Package p = ref _addr_p.val;
    ref File f = ref _addr_f.val;

    ref bytes.Buffer buf = ref heap(out ptr<bytes.Buffer> _addr_buf);

    fmt.Fprintf(_addr_buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n");
    fmt.Fprintf(_addr_buf, "// %s %s\n", filepath.Base(os.Args[0]), strings.Join(os.Args[(int)1..], " "));
    fmt.Fprintf(_addr_buf, "\n");

    var @override = make_map<@string, @string>(); 

    // Allow source file to specify override mappings.
    // For example, the socket data structures refer
    // to in_addr and in_addr6 structs but we want to be
    // able to treat them as byte arrays, so the godefs
    // inputs in package syscall say
    //
    //    // +godefs map struct_in_addr [4]byte
    //    // +godefs map struct_in_addr6 [16]byte
    //
    foreach (var (_, g) in f.Comments) {
        foreach (var (_, c) in g.List) {
            var i = strings.Index(c.Text, "+godefs map");
            if (i < 0) {
                continue;
            }
            var s = strings.TrimSpace(c.Text[(int)i + len("+godefs map")..]);
            i = strings.Index(s, " ");
            if (i < 0) {
                fmt.Fprintf(os.Stderr, "invalid +godefs map comment: %s\n", c.Text);
                continue;
            }
            override["_Ctype_" + strings.TrimSpace(s[..(int)i])] = strings.TrimSpace(s[(int)i..]);
        }
    }    {
        var n__prev1 = n;

        foreach (var (_, __n) in f.Name) {
            n = __n;
            {
                var s__prev1 = s;

                s = override[n.Go];

                if (s != "") {
                    override[n.Mangle] = s;
                }
                s = s__prev1;

            }
        }
        n = n__prev1;
    }

    var refName = make_map<ptr<ast.Expr>, ptr<Name>>();
    foreach (var (_, r) in f.Ref) {
        refName[r.Expr] = r.Name;
    }    {
        var d__prev1 = d;

        foreach (var (_, __d) in f.AST.Decls) {
            d = __d;
            ptr<ast.GenDecl> (d, ok) = d._<ptr<ast.GenDecl>>();
            if (!ok || d.Tok != token.TYPE) {
                continue;
            }
            {
                var s__prev2 = s;

                foreach (var (_, __s) in d.Specs) {
                    s = __s;
                    s = s._<ptr<ast.TypeSpec>>();
                    var n = refName[_addr_s.Type];
                    if (n != null && n.Mangle != "") {
                        override[n.Mangle] = s.Name.Name;
                    }
                }
                s = s__prev2;
            }
        }
        d = d__prev1;
    }

    {
        var def__prev1 = def;

        foreach (var (__typ, __def) in typedef) {
            typ = __typ;
            def = __def;
            {
                var new__prev1 = new;

                var @new = override[typ];

                if (new != "") {
                    {
                        ptr<ast.Ident> id__prev2 = id;

                        ptr<ast.Ident> (id, ok) = def.Go._<ptr<ast.Ident>>();

                        if (ok) {
                            override[id.Name] = new;
                        }
                        id = id__prev2;

                    }
                }
                new = new__prev1;

            }
        }
        def = def__prev1;
    }

    {
        var new__prev1 = new;

        foreach (var (__old, __new) in override) {
            old = __old;
            new = __new;
            {
                ptr<ast.Ident> id__prev1 = id;

                var id = goIdent[old];

                if (id != null) {
                    id.Name = new;
                }
                id = id__prev1;

            }
        }
        new = new__prev1;
    }

    {
        ptr<ast.Ident> id__prev1 = id;

        foreach (var (__name, __id) in goIdent) {
            name = __name;
            id = __id;
            if (id.Name == name && strings.Contains(name, "_Ctype_union")) {
                {
                    var def__prev2 = def;

                    var def = typedef[name];

                    if (def != null) {
                        id.Name = gofmt(def);
                    }
                    def = def__prev2;

                }
            }
        }
        id = id__prev1;
    }

    conf.Fprint(_addr_buf, fset, f.AST);

    return buf.String();
}

private static bytes.Buffer gofmtBuf = default;

// gofmt returns the gofmt-formatted string for an AST node.
private static @string gofmt(object n) {
    gofmtBuf.Reset();
    var err = printer.Fprint(_addr_gofmtBuf, fset, n);
    if (err != null) {
        return "<" + err.Error() + ">";
    }
    return gofmtBuf.String();
}

// gofmtLineReplacer is used to put a gofmt-formatted string for an
// AST expression onto a single line. The lexer normally inserts a
// semicolon at each newline, so we can replace newline with semicolon.
// However, we can't do that in cases where the lexer would not insert
// a semicolon. We only have to worry about cases that can occur in an
// expression passed through gofmt, which means composite literals and
// (due to the printer possibly inserting newlines because of position
// information) operators.
private static var gofmtLineReplacer = strings.NewReplacer("++\n", "++;", "--\n", "--;", "+\n", "+ ", "-\n", "- ", "*\n", "* ", "/\n", "/ ", "%\n", "% ", "&\n", "& ", "|\n", "| ", "^\n", "^ ", "<\n", "< ", ">\n", "> ", "=\n", "= ", "!\n", "! ", "(\n", "(", "[\n", "[", "{\n", "{", ",\n", ",", ".\n", ". ", ":\n", ": ", "\n", ";");

// gofmtLine returns the gofmt-formatted string for an AST node,
// ensuring that it is on a single line.
private static @string gofmtLine(object n) {
    return gofmtLineReplacer.Replace(gofmt(n));
}

} // end main_package
